# -*- coding: utf-8 -*-
import itertools
from functools import partial
from decimal import Decimal

from common.lottery.cyclical.ff_pk10.model.order import BET_TYPE

RATE_CONFIG = {  # base on UNIT==2
    BET_TYPE.ONE_FRONT: 10.000,
    BET_TYPE.TWO_FRONT: 90.000,
    BET_TYPE.THREE_FRONT: 720.000,
    BET_TYPE.FOUR_FRONT: 5040.000,
    BET_TYPE.FIVE_FRONT: 30240.000,
    BET_TYPE.ONE_ANY: 10.000,
    BET_TYPE.FIRST_BSOE: 2.000,
    BET_TYPE.SECOND_BSOE: 2.000,
    BET_TYPE.THIRD_BSOE: 2.000,
    BET_TYPE.DRAGON_TIGER: 2.000,

    BET_TYPE.PLATE_BSOE_1: 2.000,
    BET_TYPE.PLATE_BSOE_2: 2.000,
    BET_TYPE.PLATE_BSOE_3: 2.000,
    BET_TYPE.PLATE_BSOE_4: 2.000,
    BET_TYPE.PLATE_BSOE_5: 2.000,
    BET_TYPE.PLATE_BSOE_6: 2.000,
    BET_TYPE.PLATE_BSOE_7: 2.000,
    BET_TYPE.PLATE_BSOE_8: 2.000,
    BET_TYPE.PLATE_BSOE_9: 2.000,
    BET_TYPE.PLATE_BSOE_10: 2.000,

    BET_TYPE.PLATE_DRAGON_TIGER_1v10: 2.000,
    BET_TYPE.PLATE_DRAGON_TIGER_2v9: 2.000,
    BET_TYPE.PLATE_DRAGON_TIGER_3v8: 2.000,
    BET_TYPE.PLATE_DRAGON_TIGER_4v7: 2.000,
    BET_TYPE.PLATE_DRAGON_TIGER_5v6: 2.000,
}

UNIT = 2  # 彩票单价


def valid_number(bet_type, number):
    '''同一位之间用','隔开
       不同位之间用'|'隔开
       与顺序无关的选项，使用','隔开
    '''
    positions = number.split('|')
    nums = []
    for position in positions:
        if not position:
            continue
        ds = position.split(',')
        for d in ds:
            if BET_TYPE.FIRST_BSOE <= bet_type <= BET_TYPE.THIRD_BSOE:
                # big: 大, small: 小, odd: 单, even: 双
                assert d in ('b', 's', 'o', 'e'), 'bsoe number format wrong'
            elif bet_type == BET_TYPE.DRAGON_TIGER:
                assert d in ('d', 't'), 'dragon tiger number format wrong'
            elif bet_type in [BET_TYPE.PLATE_DRAGON_TIGER_1v10, BET_TYPE.PLATE_DRAGON_TIGER_2v9,
                              BET_TYPE.PLATE_DRAGON_TIGER_3v8, BET_TYPE.PLATE_DRAGON_TIGER_4v7,
                              BET_TYPE.PLATE_DRAGON_TIGER_5v6]:
                assert d in ('d', 't'), 'PLATE_DRAGON_TIGER_1v10 number format wrong'
                return
            elif bet_type in [BET_TYPE.PLATE_BSOE_1, BET_TYPE.PLATE_BSOE_2, BET_TYPE.PLATE_BSOE_3,
                              BET_TYPE.PLATE_BSOE_4,
                              BET_TYPE.PLATE_BSOE_5, BET_TYPE.PLATE_BSOE_6, BET_TYPE.PLATE_BSOE_7,
                              BET_TYPE.PLATE_BSOE_8,
                              BET_TYPE.PLATE_BSOE_9, BET_TYPE.PLATE_BSOE_10]:
                assert d in ('b', 's', 'o', 'e'), 'PLATE_BSOE  format wrong'
                return
            else:
                assert 1 <= int(d) <= 10, 'number range error'
        nums.append(ds)
    if BET_TYPE.ONE_FRONT <= bet_type <= BET_TYPE.FIVE_FRONT:
        assert len(positions) == bet_type, 'need %s `|`' % bet_type
        for num in nums:
            assert 10 >= len(num) >= 1, 'number format wrong'
    elif BET_TYPE.FIRST_BSOE <= bet_type <= BET_TYPE.DRAGON_TIGER:
        assert len(positions) == 1 and len(nums) >= 1, \
            'number format error'
    elif bet_type == BET_TYPE.ONE_ANY:
        assert len(positions) == 10 and len(nums) >= 1, 'format wrong'
    else:
        assert False, 'bet_type invalid'


def calc_total_price(bet_type, number, times=1, unit=UNIT):
    """根据不同的竞猜方式计算所需总价
    """
    positions = number.split('|')
    nums = []
    for position in positions:
        if not position:
            continue
        ds = position.split(',')
        nums.append(ds)
    if bet_type in (BET_TYPE.TWO_FRONT, BET_TYPE.THREE_FRONT, BET_TYPE.FOUR_FRONT, BET_TYPE.FIVE_FRONT):
        price = 0
        for item in itertools.product(*nums):
            if len(set(item)) == len(item):
                price += 1
    elif bet_type == BET_TYPE.ONE_ANY:
        price = 0
        for num in nums:
            price += len(num)
    else:
        price = 1
        for num in nums:
            price *= len(num)
    return price * times * unit


def generate_win_func(number):
    '''根据开奖结果生成根据押注方式对应的中奖函数，避免重复计算
    '''
    result = {}
    numbers = number.split(',')

    def n_front(front_x, x):
        """
        front_x == 1  猜冠军
        front_x == 2  猜前二
        front_x == 3  猜前三
        """
        positions = x.split('|')
        hit = 0
        for index, position in enumerate(positions):
            nums = position.split(',')
            if numbers[index] in nums:
                hit += 1
        return 1 if hit == front_x else 0

    for k in range(BET_TYPE.ONE_FRONT, BET_TYPE.FIVE_FRONT + 1):
        result[k] = partial(n_front, k)

    def one_any(x):
        xs = x.split('|')
        r = 0
        for i, v in enumerate(xs):
            hit = int(numbers[i])
            if v and hit in [int(x) for x in v.split(',')]:
                r += 1
        return r

    result[BET_TYPE.ONE_ANY] = one_any

    def bsoe(idx, x):
        desc = set()
        letter = numbers[idx]
        n = int(letter)
        if n >= 6:
            desc.add('b')
        else:
            desc.add('s')
        if n % 2 == 0:
            desc.add('e')
        else:
            desc.add('o')

        hit = len(set(x) & desc)
        return hit

    result[BET_TYPE.FIRST_BSOE] = partial(bsoe, 0)
    result[BET_TYPE.SECOND_BSOE] = partial(bsoe, 1)
    result[BET_TYPE.THIRD_BSOE] = partial(bsoe, 2)

    def dragon_tiger(x):
        guesses = x.split(',')
        if int(numbers[0]) > int(numbers[-1]):
            result = 'd'
        else:
            result = 't'
        return 1 if result in guesses else 0

    result[BET_TYPE.DRAGON_TIGER] = dragon_tiger

    def n_plate_dragon_tiger(n, x):
        guesses = x.split(',')
        dragon = int(numbers[n])
        tiger = int(numbers[-(n + 1)])
        if dragon > tiger:
            res = 'd'
        elif dragon < tiger:
            res = 't'
        else:
            res = 'h'
        return 1 if res in guesses else 0

    result[BET_TYPE.PLATE_DRAGON_TIGER_1v10] = partial(n_plate_dragon_tiger, 0)
    result[BET_TYPE.PLATE_DRAGON_TIGER_2v9] = partial(n_plate_dragon_tiger, 1)
    result[BET_TYPE.PLATE_DRAGON_TIGER_3v8] = partial(n_plate_dragon_tiger, 2)
    result[BET_TYPE.PLATE_DRAGON_TIGER_4v7] = partial(n_plate_dragon_tiger, 3)
    result[BET_TYPE.PLATE_DRAGON_TIGER_5v6] = partial(n_plate_dragon_tiger, 4)

    def n_plate_bsoe(n, x):
        num = int(numbers[n])
        desc = set()
        if num > 5:
            desc.add('b')
        else:
            desc.add('s')
        if num % 2 == 0:
            desc.add('e')
        else:
            desc.add('o')
        guesses = x.split('|')
        hit = 1
        for i, guess in enumerate(guesses):
            t = guess.split(',')
            hit *= len(set(t) & desc)
        return hit

    result[BET_TYPE.PLATE_BSOE_1] = partial(n_plate_bsoe, 0)
    result[BET_TYPE.PLATE_BSOE_2] = partial(n_plate_bsoe, 1)
    result[BET_TYPE.PLATE_BSOE_3] = partial(n_plate_bsoe, 2)
    result[BET_TYPE.PLATE_BSOE_4] = partial(n_plate_bsoe, 3)
    result[BET_TYPE.PLATE_BSOE_5] = partial(n_plate_bsoe, 4)
    result[BET_TYPE.PLATE_BSOE_6] = partial(n_plate_bsoe, 5)
    result[BET_TYPE.PLATE_BSOE_7] = partial(n_plate_bsoe, 6)
    result[BET_TYPE.PLATE_BSOE_8] = partial(n_plate_bsoe, 7)
    result[BET_TYPE.PLATE_BSOE_9] = partial(n_plate_bsoe, 8)
    result[BET_TYPE.PLATE_BSOE_10] = partial(n_plate_bsoe, 9)

    return result


def calc_win_price(funcs, bet_number, bet_type, times=1, unit=UNIT,
                   rate_config=RATE_CONFIG):
    '''根据开奖结果和押注方式/倍数，计算中奖金额
    '''
    func = funcs.get(bet_type)
    base = func(bet_number) * Decimal(rate_config.get(bet_type))
    return Decimal(base) * Decimal(times) * Decimal(unit) / Decimal(UNIT)
